﻿using System;
using System.Collections.Generic;
//using System.Linq;
using System.Windows.Forms;
using System.Drawing; //For Color(s) class
using System.Diagnostics; //for debugging
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
//using Microsoft.DirectX.DirectInput;
//using Microsoft.DirectX.DirectPlay;
//using Microsoft.DirectX.DirectSound;
//using Microsoft.DirectX.AudioVideoPlayback;
using DirectX_CS;

//www reference: 	http://www.c-sharpcorner.com/Blogs/BlogDetail.aspx?BlogId=71

namespace DirectX_CS
{

	class DirectXWindow
	{
		public Device mDxDevice = null;
		public Form  mFrm = null;
		
		private bool exitProgram = false;
		public bool mExitProgram
		{
			get { return exitProgram; }
			set { exitProgram = value; }
		}

		private Material mMeshMaterial; //see InitializeForm, not nullable
		public Material MeshMaterial
		{
			get { return mMeshMaterial; }
			set { mMeshMaterial = value; }
		}
		Viewport viewPort;
		Terrain mTerrain;

		public bool ExitProgram
		{
			get { return exitProgram; }
			set 
			{ 
				exitProgram = value; 
			}
		}
		
		DirectXWindow() //Empty constructor
		{  Initialize(null,null); }

		//Constructor of the two required pieces in order for the system to work.
		DirectXWindow(Device dev, Form display)
		{
			Initialize(dev, display); //see Initialize...
		}

		
		/// <summary>
		/// Called during construction primarily to make sure that
		/// the paramaters are not null. If Form is null then the 
		/// we create the default form. If the Device is null then
		/// we create a working graphics device.
		/// Also wires up the form to the program shutdown mechanism.
		/// 
		/// //NOTE: create your Device and display first
		/// </summary>
		/// <param name="dev">if null is used for a device or form then the device or form will be created!</param>
		/// <param name="display">if null is used for a device or form then the device or form will be created!</param>
		void Initialize(Device dev, Form displayForm)
		{
			//CreateDevice requires the form be created first!, 
			if (displayForm == null) 
				mFrm = new frmDirectX();
			if (dev == null)
				mDxDevice = CreateDevice(); //CreateDevice requires the form be created before the 'Device'!, 

			//add a form closed handler to the directx window host
			mFrm.FormClosing += new FormClosingEventHandler(frm_FormClosing); 
			//end add form handlers

			mDxDevice.RenderState.Lighting = true;
			mDxDevice.RenderState.CullMode = Cull.None;
			mDxDevice.RenderState.ZBufferEnable = true;
			mDxDevice.RenderState.FillMode = FillMode.WireFrame;
			mDxDevice.RenderState.DepthBias = 0.1F;

			//now that we have the device pass its reference along
			mTerrain = new Terrain(mDxDevice);

			//InitializeLighting();
			InitializeMaterials(); //initialize materials after lighting
			SetViewport();

		}

		void InitializeMaterials()
		{
			mMeshMaterial = new Material();
			//meshMaterial.Specular = Color.Blue;
			//mMeshMaterial.Diffuse = Color.Blue;
			mMeshMaterial.Ambient = Color.Blue;
			mDxDevice.Material = mMeshMaterial;
		}

		//setup the lights and lighting to be used 
		void InitializeLighting()
		{
			if (mDxDevice.Lights.Count != 0) //check the lights (count) duh.
			{
				Light L = mDxDevice.Lights[0];
				L.Ambient = Color.White;
				//L.Specular = Color.White;
				//L.Diffuse = Color.White;
				L.Position = new Vector3(0, 0, 0); //center of light/screen
				L.Direction = new Vector3(0, 0, -1);
				L.Type = LightType.Directional;
				L.Enabled = true;
			}
		}
		/// <summary>
		/// Attempts to play with the "camera"
		/// </summary>
		void SetViewport()
		{
			//setup viewport
			viewPort = new Viewport();
			viewPort.X = 0;
			viewPort.Y = 0;
			viewPort.Width = 1;
			viewPort.Height = 1;
			viewPort.MinZ = -1;
			viewPort.MaxZ = 0;
			mDxDevice.Viewport = viewPort;


			//Transform.View = camera.ViewMatrix;
			//mDxDevice.Transform.Projection = camera.ProjectionMatrix;
			//mDxDevice.Transform.World = Matrix.RotationX((float)appTime);
		}

		void frm_FormClosing(object sender, FormClosingEventArgs e)
		{
			exitProgram = true;
		}

	/// <summary>
	/// Good old static void Main... first part of the program to be run, 
	/// </summary>
	static void Main() //do not modify, use Render
	{
			DirectXWindow dxWin = null;
			dxWin = new DirectXWindow();
			dxWin.mFrm.Show();

			///Begin runing standard managed Windows loop.
			while (!dxWin.ExitProgram) 
			{
			    dxWin.RenderScene(); //use this, but dont modify the order of the statments in this loop.
			    dxWin.Present();
				Application.DoEvents(); //end run standard managed windows loop
			}
		}
		////
		////
		/// <summary>
		/// Just a notational device.
		/// </summary>
		void Present()
		{
			mDxDevice.Present();
		}

		/// <summary>
		/// //THIS IS AN IMPORTANT RENDER DISPLAY METHOD!
		/// //It is called frequently in terms of video card speeds.
		/// </summary>
		public void RenderScene()
		{
			
			mDxDevice.BeginScene();
			mDxDevice.Clear(ClearFlags.Target, Color.White, 0, 0);
			SetViewport();
			//render the TEST MESH
			mTerrain.DrawMesh();
			mDxDevice.EndScene();
		}


	}
}